#ifndef LOGGER_H
#define LOGGER_H


#include <cstdio>
#include <cstring>
#include <cstdarg>
#include <string>
#include <cassert>
#include <unistd.h>
#include "block_queue.h"

using namespace std;

class Logger {
public:
    static Logger *get_instance();

    bool init(const char *file_name, int split_lines=100,
              int buf_size=8192, int queue_capacity=100);
    void write_log(int level, const char *format, ...);
    static void *flush_worker(void *arg);
    void flush();
    bool is_open() const {return !m_is_close;}
    void close();


private:
    Logger();
    ~Logger();

    void async_write();

private:
    char m_dir_name[128];
    char m_log_name[128];
    int m_split_lines;
    int m_buf_size;
    long long m_lines;
    int m_today;
    FILE *m_file;
    BlockQueue<string> *m_log_queue;
    bool m_async_mode;
    bool m_is_close;
    Locker m_file_lock;
    pthread_t m_worker_id;
};


#define LOG_BASE(level, format, ...) \
        do {                         \
            if (Logger::get_instance()->is_open()) { \
                Logger::get_instance()->write_log(level, format, ##__VA_ARGS__); \
            } \
        } while(0)


#define LOG_DEBUG(format, ...) \
        do { \
            LOG_BASE(0, format, ##__VA_ARGS__); \
        } while(0);

#define LOG_INFO(format, ...) \
        do { \
            LOG_BASE(1, format, ##__VA_ARGS__); \
        } while(0);

#define LOG_WARN(format, ...) \
        do { \
            LOG_BASE(2, format, ##__VA_ARGS__); \
        } while(0);

#define LOG_ERROR(format, ...) \
         do { \
            LOG_BASE(3, format, ##__VA_ARGS__); \
        } while(0);


#endif //LOGGER_H
